package application.services;

import application.exceptions.ItemNotFoundException;
import application.model.MaterialWithParametersModel;
import application.model.MaterialsModel;
import application.model.modify.MaterialModel;
import application.model.wrappers.MaterialWithParametersWrapper;
import application.translators.Translator;
import application.translators.impl.MaterialWithParametersTranslator;
import application.translators.impl.MaterialsTranslator;
import dao.AppliancesCompositionDao;
import dao.MaterialsDao;
import dao.MaterialsDefinitionDao;
import mappings.AppliancesComposition;
import mappings.Material;
import mappings.Standards;
import org.hibernate.exception.ConstraintViolationException;
import utils.FeatureNamesHolder;
import utils.MergeUtil;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;

@Path("materials")
public class MaterialService
{
    private MaterialsDefinitionDao materialDefinitionsDao = new MaterialsDefinitionDao();
    private MaterialsDao materialsDao = new MaterialsDao();
    private AppliancesCompositionDao appliancesCompositionDao = new AppliancesCompositionDao();
    private Translator<Object[], MaterialWithParametersModel> withParametersTranslator = new MaterialWithParametersTranslator();
    private Translator<List<Material>, MaterialsModel> translator = new MaterialsTranslator();

    @Path("testService")
    @GET
    public Response testService()
    {
        return Response.status(200).entity("Service is working!").build();
    }

    @Path("getAllMaterials")
    @GET
    @Produces(MediaType.APPLICATION_XML)
    public MaterialsModel getAllMaterials()
    {
        return translator.translate(materialsDao.getAllMaterials());
    }

    /*
     * Zwraca XML dla wszystkich materialow wraz z parametrami
     */
    @Path("getMaterialsWithParameters")
    @GET
    @Produces(MediaType.APPLICATION_XML)
    public MaterialWithParametersWrapper getMaterialsWithParameters()
    {
        MaterialWithParametersWrapper materialWithParametersWrapper = new MaterialWithParametersWrapper();
        List<Object[]> materials = materialDefinitionsDao.getDistinctMaterialDefinitions();

        for(Object[] material : materials)
        {
            Material materialEntity = (Material) material[0];
            Standards standardsEntity = (Standards) material[1];

            Object[] materialWithParameters = new Object[20];

            materialWithParameters[0] = materialEntity.getId();
            materialWithParameters[1] = materialEntity.getName();
            materialWithParameters[2] = standardsEntity.getName();

            Object[] feature;

            feature = materialDefinitionsDao.getMaterialDefinitionWithFeature(materialEntity, standardsEntity, FeatureNamesHolder.RM);

            materialWithParameters[3] = feature[0];
            materialWithParameters[4] = feature[1];

            feature = materialDefinitionsDao.getMaterialDefinitionWithFeature(materialEntity, standardsEntity, FeatureNamesHolder.RP02);

            materialWithParameters[5] =  feature[0];
            materialWithParameters[6] = feature[1];

            feature = materialDefinitionsDao.getMaterialDefinitionWithFeature(materialEntity, standardsEntity, FeatureNamesHolder.A5);

            materialWithParameters[7] = feature[0];
            materialWithParameters[8] = feature[1];

            feature = materialDefinitionsDao.getMaterialDefinitionWithFeature(materialEntity, standardsEntity, FeatureNamesHolder.HB);

            materialWithParameters[9] = feature[0];
            materialWithParameters[10] = feature[1];

            feature = materialDefinitionsDao.getMaterialDefinitionWithFeature(materialEntity, standardsEntity, FeatureNamesHolder.HRC);

            materialWithParameters[11] = feature[0];
            materialWithParameters[12] = feature[1];

            feature = materialDefinitionsDao.getMaterialDefinitionWithFeature(materialEntity, standardsEntity, FeatureNamesHolder.KC);

            materialWithParameters[13] = feature[0];
            materialWithParameters[14] = feature[1];

            feature = materialDefinitionsDao.getMaterialDefinitionWithFeature(materialEntity, standardsEntity, FeatureNamesHolder.KCV);

            materialWithParameters[15] = feature[0];
            materialWithParameters[16] = feature[1];

            String producents =  MergeUtil.mergeProducentsIntoOneString(materialEntity.getProducentCompositions());
            String types = MergeUtil.mergeTypesIntoOneString(materialEntity.getTypesCompositions());

            List<AppliancesComposition> appliancesCompositions = appliancesCompositionDao.getAppliancesCompositionForMaterialAndStandard(materialEntity, standardsEntity);
            String appliances = MergeUtil.mergeAppliancesIntoOneString(appliancesCompositions);

            materialWithParameters[17] = producents;
            materialWithParameters[18] = types;
            materialWithParameters[19] = appliances;

            materialWithParametersWrapper.addMaterialWithParameters(withParametersTranslator.translate(materialWithParameters));

        }

        return materialWithParametersWrapper;
    }

    @Path("addMaterial")
    @POST
    @Produces(MediaType.APPLICATION_XML)
    public MaterialModel addNewMaterial(@FormParam("name") String name)
    {
        MaterialModel materialModel = new MaterialModel();

        try
        {
            Material material = materialsDao.addMaterial(name);
            materialModel.setId(material.getId());
            materialModel.setName(material.getName());
            materialModel.setStatus(0);
        }
        catch (ConstraintViolationException e)
        {
            // lapiemy wyjatek rzucany przez hibernate'a dla unique constraint - ustawiamy status 1 (rekord istnieje)
            materialModel.setStatus(1);
        }
        catch (Exception e)
        {
            // lapiemy wszystkie inne exceptiony i ustawiamy status na 2 (czyli cos sie wyjebalo, ale nie wiadomo co :P)
            materialModel.setStatus(2);
        }

        return materialModel;
    }

    @Path("editMaterial")
    @POST
    @Produces(MediaType.APPLICATION_XML)
    public MaterialModel editMaterial(@FormParam("id") Integer id, @FormParam("name") String name)
    {
        MaterialModel materialModel = new MaterialModel();

        try
        {
            Material material = materialsDao.editMaterial(id, new Material(name));
            materialModel.setName(material.getName());
            materialModel.setId(material.getId());
            materialModel.setStatus(0);
        }
        catch (ItemNotFoundException e)
        {
            materialModel.setStatus(1); // 1 = nie znaleziono rekordu o danym id
        }
        catch (Exception e)
        {
            materialModel.setStatus(2);
        }

        return materialModel;
    }

    @Path("deleteMaterial")
    @POST
    @Produces(MediaType.APPLICATION_XML)
    public MaterialModel deleteMaterial(@FormParam("id") Integer id)
    {
        MaterialModel materialModel = new MaterialModel();

        try
        {
            materialsDao.deleteMaterial(id);
            materialModel.setStatus(0);
        }
        catch (ItemNotFoundException e)
        {
            materialModel.setStatus(1); // 1 = nie znaleziono rekordu o danym id
        }
        catch (Exception e)
        {
            materialModel.setStatus(2);
        }

        return materialModel;
    }
}
